/***************************************************************************************** 
*                                     TinyRtos51 
*                                The Real-Time Kernel 
*                              Copyright(c) 2024 fanxsp
*                         SPDX-License-Identifier: APACHE-2.0
*       This software is subject to an open source license and is distributed by fanxsp,
*       pursuant to the terms of the Apache License.
******************************************************************************************/
/***************************************************************************************** 
* 				TinyRtos51 OSSem.c
* Author: fanxsp 
* Revision: 1.00
* Date: 2023-09-16
* 
******************************************************************************************/
#define __IN_OSSEM_C
#include "tinyrtos51.h"

#if OSSEMS > 0

/* 每个Sem占用1 byte */
OStypeInt8u OSLOC_SEM OSSemArea[OSSEMS] ;

/* API */
/******************************************************************************************
* 初始化信号量  在OSStart()前调用
* 参数：eID  信号量ID   value 初始值
*******************************************************************************************/
void OSInitSem(OStypeInt8u eID,OStypeInt8u value) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSSEMS-1) return ;
#endif
	OSSemArea[eID] = value  ;
}

/******************************************************************************************
* 等待信号量  在任务中调用 不能在中断中调用
* 参数：eID  信号量ID   ticks 超时时间  =0 为永久等待
*******************************************************************************************/
#if OSBYTES_OF_DELAYS > 0
void OSWaitSem(OStypeInt8u eID,OStypeOfDelays ticks) 
#else
void OSWaitSem(OStypeInt8u eID) 	
#endif
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSSEMS-1) return ;
#endif

	OSEnterCritical() ;
#if OSBYTES_OF_DELAYS > 0
	OSTcbArea[OSTaskRunning].timeout = 0 ;
#endif
	if(OSSemArea[eID] == 0)
	{
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[OSTaskRunning].delay = ticks ;
#endif
		OSTcbArea[OSTaskRunning].state = OSTCB_WAITING ;
		ACC = eID ;
		_push_(ACC) ;
		OSDelFromList(OSTaskRunning) ;
		eID = *(OStypeInt8u idata *)SP ;
		OSAppendToList(OSHeadSem(eID),OSTaskRunning) ;
		OSTaskSw() ;
		_pop_(ACC) ;
		eID = ACC ;
	}
	else OSSemArea[eID]-- ;
	OSExitCritical() ;
}

/******************************************************************************************
* 测试信号量 并减1  可以在中断中调用
* 参数：eID  信号量ID 
* 返回：信号量状态
*******************************************************************************************/
OStypeInt8u OSTrySem(OStypeInt8u eID) 
{
	OStypeInt8u tmp ;
	
	tmp = 0 ;
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSSEMS-1) return tmp ;
#endif
	OSEnterCritical() ;
	if(OSSemArea[eID] > 0)
	{
		tmp = 1 ;
		OSSemArea[eID]-- ;
	}
	OSExitCritical() ;
	return tmp ;
}

/*******************************************************************************************
* 读取信号量 不清零  可以在中断中调用
* 参数：eID  信号量ID 
* 返回：信号量值
********************************************************************************************/
OStypeInt8u OSReadSem(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSSEMS-1) return 0 ;
#endif
	return OSSemArea[eID]  ; 
}

/********************************************************************************************
* 发送信号量 公共代码 信号量最大值为255 超出最大值 发送操作被忽略 不含临界保护 不能直接调用
* 参数：eID 信号量ID 
*********************************************************************************************/
void OSSignalSem(OStypeInt8u eID) 
{
	OStypeInt8u tmp ;

	if(OSHeadSem(eID) != OSListArea[OSHeadSem(eID)].next)
	{
		tmp = OSHiPrioInList(OSHeadSem(eID)) ;
		OSTcbArea[tmp].state = OSTCB_ELIGIBLE ;
#if OSBYTES_OF_DELAYS > 0
		OSTcbArea[tmp].delay = 0 ;
#endif
//		SP++ ;
//		*(OStypeInt8u idata *)SP = tmp ;
		OSDelFromList(tmp) ;
//		tmp = *(OStypeInt8u idata *)SP ;
//		SP-- ;
		OSAppendToList(OSHeadEligible,tmp) ;
	}
	else OSSemArea[eID]++ ;
}

/*********************************************************************************************
* 在中断中发送信号量  信号量最大值为255 超出最大值 发送操作被忽略
* 参数：eID 信号量ID 
**********************************************************************************************/
void OSIntSignalSem(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSSEMS-1) return ;
	if(OSSemArea[eID] == 0xff) return ;
#endif
	OSEnterCritical() ;
	OSSignalSem(eID) ;
#if OSMETHOD > 0
	OSPendSVAct() ;
#endif
	OSExitCritical() ;
}

/**********************************************************************************************
* 在任务中发送信号量  信号量最大值为255 超出最大值 发送操作被忽略
* 参数：eID  信号量ID 
***********************************************************************************************/
void OSTaskSignalSem(OStypeInt8u eID) 
{
#if OSENABLE_ERROR_CHECKING > 0
	if(eID > OSSEMS-1) return ;
	if(OSSemArea[eID] == 0xff) return ;
#endif
	OSEnterCritical() ;
	OSSignalSem(eID) ;
#if OSMETHOD > 0
	OSTaskSw() ;
#endif
	OSExitCritical() ;
}

#endif